import {IParams} from './params'
import path from 'path'
import * as fs from 'fs-extra'
import * as step from '@flow-step/step-toolkit'
import process from 'process'
import {findEslintrcFiles, readFile} from './utils'

export async function scan(params: IParams, DependencyDir:string) {

    const copiedScanDir = path.join(params.pluginDir,'js-codescan','code_origin')
    fs.mkdirSync(copiedScanDir,{ recursive: true })
    //use fs-extra to copy the entire dir
    fs.copySync(params.projectDir,copiedScanDir,{overwrite:true})

    const codeForDisplay = path.join(params.pluginDir,'js-codescan','repocode') // do not change the dir name, html depends on it
    fs.mkdirSync(codeForDisplay,{ recursive: true })
    fs.copySync(params.projectDir,codeForDisplay,{overwrite:true})

    let exitCode:number
    let scanPath:string
    if (!params.incrementalScan){
        step.info(`not use incrementalScan`)
        scanPath = copiedScanDir
    }else {
        step.info(`use incrementalScan`)
        scanPath = path.join(params.pluginDir, 'codescan', 'code')
        fs.mkdirSync(scanPath, {recursive: true})
        const commitInfoPath = path.join(params.projectDir, '..', 'commitInfo')
        if (process.env.FLOW_RUNNER_DEBUG) {
            const commitInfoData = fs.readFileSync(commitInfoPath, 'utf-8')
            step.debug('commitInfo: ' + commitInfoData)
        }
        const fileListPath = path.join(DependencyDir, 'fileList.txt')
        const diffResultPath = path.join(DependencyDir, 'diff_result.json')
        step.info(`${path.join(DependencyDir, 'diff')} -c ${commitInfoPath} -s ${params.projectDir} -f js -o ${diffResultPath} -l ${fileListPath}`)
        exitCode = await step.exec.call(path.join(DependencyDir, 'diff'), ['-c', commitInfoPath, '-s', params.projectDir, '-f', 'js', '-o', diffResultPath, '-l', fileListPath], {
            listener: {
                stdoutLine: (line: string) => step.info(line),
                stderrLine: (line: string) => step.error(line)
            }
        })
        if (exitCode !== 0) {
            throw new Error(`diff exec failed, exit code: ${exitCode}`)
        }

        if (fs.existsSync(fileListPath)) {
            const fileList = fs.readFileSync(fileListPath, 'utf-8').trim();
            step.debug(`fileList: ${fileList}`)
            if (fileList === '') {
                step.info('Diff list is empty. No JavaScript file changes found')
            } else {
                step.info('---Files to scan---')
                const files = fileList.split(' ');
                step.debug(`files: ${files}`)
                for (const file of files) {
                    const trimmedFile = file.trim();
                    const filePath = path.join(copiedScanDir, trimmedFile);
                    step.debug(`filePath: ${filePath}`)

                    if (fs.existsSync(filePath)) {
                        step.info(filePath);
                        const relativePath = path.dirname(trimmedFile);
                        const destDir = path.join(scanPath, relativePath);
                        if (!fs.existsSync(destDir)) {
                            fs.mkdirSync(destDir, { recursive: true });
                        }
                        fs.copyFileSync(filePath, path.join(scanPath, trimmedFile));
                    }
                }
                step.info('-------------------')

                if (fs.existsSync(path.join(copiedScanDir, 'package.json'))){
                    fs.copyFileSync(path.join(copiedScanDir, 'package.json'), path.join(scanPath, 'package.json'));
                }

                if (params.useLocalRules) {
                    const eslintrcFiles = findEslintrcFiles(copiedScanDir);
                    step.info(`Found .eslintrc.* file(s): ${eslintrcFiles}`);
                    if (eslintrcFiles) {
                        eslintrcFiles.forEach(file => {
                            const destPath = path.join(scanPath, path.basename(file));
                            fs.copyFileSync(file, destPath);
                        });
                    }
                }
            }
        }else{
            step.info('No JavaScript file changes detected')
        }
    }

    const issuePath = path.join(DependencyDir,'issues.json')
    step.info(`node ./code-quality-eslint -p "rdc" -e "${params.exclusion}" -l "${params.useLocalRules}" -d "${params.localDependencies}" -r "" -s "${scanPath}" -t "all" -u "" -i "${issuePath}"`)
    exitCode = await step.exec.call('node',[
        './code-quality-eslint',
        '-p',`\"rdc\"`,
        '-e',`\"${params.exclusion}\"`,
        '-l',`\"${params.useLocalRules}\"`,
        '-d',`\"${params.localDependencies}\"`,
        '-r',`\"\"`,
        '-s',`\"${scanPath}\"`,
        '-t',`\"all\"`,
        '-u',`\"\"`,
        '-i',`\"${issuePath}\"`
    ],{
        listener: {
            stdoutLine: (line: string) => step.info(line),
            stderrLine: (line: string) => {
                // code-quality-eslint会检验tnpm版本
                if (!line.includes('tnpm')) {
                    step.error(line)
                }
            }
        },
        cwd: DependencyDir
    })
    if (exitCode !== 0) {
        throw new Error(`diff exec failed, exit code: ${exitCode}`)
    }
    if (step.isDebug()){
        const issue = await readFile(issuePath)
        step.debug(`issue.json: ${issue}`);
    }

    const flowJobToken: string | undefined =
        process.env['FLOW_JOB_TOKEN']
    if (flowJobToken == undefined) {
        const errMsg = 'missing FLOW_JOB_TOKEN'
        throw new Error(errMsg)
    }
    const ossRamStsCertificate = await step.certificate.getOssRamStsCertificate(flowJobToken, step.certificate.OssBucketType.ASSETS)
    if (ossRamStsCertificate === undefined || ossRamStsCertificate.accessKeyId === "") {
        throw new Error(`get ossRamStsCertificate but error: ${JSON.stringify(ossRamStsCertificate)}`)
    }

    let endpoint = await step.oss.getEndpoint(process.env['ENDPOINT'] as string)
    if (!endpoint.startsWith('http://') && !endpoint.startsWith('https://')) {
        endpoint = 'https://' + endpoint;
    }
    step.info(`endpoint: ${endpoint}`)

    exitCode = await step.exec.call('./builder',[
        '-m','report-template.html',
        '-d','issues.json',
        '-o','index.html',
        '-c',path.basename(codeForDisplay),
        '--diff','', // compatible with v1, not use diff
        '--region',ossRamStsCertificate.ossPathPrefix,
        '--pipeline',params.pipelineID.toString(),
        '--step',params.stepIdentifier,
        '--accessKeyId',ossRamStsCertificate.accessKeyId,
        '--accessKeySecret',ossRamStsCertificate.accessKeySecret,
        '--token',ossRamStsCertificate.securityToken,
        '--bucket',ossRamStsCertificate.bucketName,
        '--endpoint',endpoint,
        '--redlines',params.redline
    ],{
        listener: {
            stdoutLine: (line: string) => {
                step.addOutput(line);
                step.info(`${line}`);
            },
            stderrLine: (line: string) => step.error(line),
        },
        cwd: DependencyDir
    })
    if (exitCode !== 0) {
        throw new Error(`builder exec failed, exit code: ${exitCode}`)
    }
    step.addOutput(`[${process.env['stepIdentifier']}]STAT_INFO_TITLE:${process.env['name']}`)
}